class LoggedMappingMixin:
    '''
    首先是，混入类不能直接被实例化使用。
    其次，混入类没有自己的状态信息，也就是说它们并没有定义 __init__() 方法，并且没有实例属性。
    这也是为什么我们在上面明确定义了 __slots__ = () 。
    '''

    '''
    __getitem__(self,key):返回键对应的值。
    __setitem__(self,key,value)：设置给定键的值
    __delitem__(self,key):删除给定键对应的元素。
    
    
    __getattr__内置使用点号获取实例属性属性如 s.name，自调用__getattr__
    __setattr__设置类实例属性 如s.name='tom'，自调用__setattr__
    __getitem__ 使用[]获取实例属性 如s['name']，自调用__getitem__
    __setitem__ 使用[]设置实例属性如 s['name'] = 'tom' ，自调用__setitem__
    __dict__ 为参数字典

    '''
    __slots__ = ()  # 混入类都没有实例变量，因为直接实例化混入类没有任何意义

    def __getitem__(self, key):
        print('Getting ' + str(key))
        return super().__getitem__(key)  # 这里相当于是基类的super()，其实基类没有__getitem__方法,直接实例化会报异常

    def __setitem__(self, key, value):
        print('Setting {} = {!r}'.format(key, value))
        return super().__setitem__(key, value)

    def __delitem__(self, key):
        print('Deleting ' + str(key))
        return super().__delitem__(key)


class SetOnceMappingMixin:
    '''
    Only allow a key to be set once.
    '''
    __slots__ = ()

    def __setitem__(self, key, value):
        if key in self:
            raise KeyError(str(key) + ' already set')
        return super().__setitem__(key, value)


class StringKeysMappingMixin:
    '''
    Restrict keys to strings only
    '''
    __slots__ = ()

    def __setitem__(self, key, value):
        if not isinstance(key, str):
            raise TypeError('keys must be strings')
        return super().__setitem__(key, value)


####准备好了吗，Mixins要来了######
class LoggedDict(LoggedMappingMixin, dict):
    pass



####第二种方式：使用类装饰器"#######没有看懂哦~
def LoggedMapping(cls):
    cls_getitem = cls.__getitem__
    cls_setitem = cls.__setitem__
    cls_delitem = cls.__delitem__
    def __getitem__(self,key):
        print('Getting ' + str(key))
        return cls_getitem(self,key)

    def __setitem__(self, key, value):
        print('Setting {} = {!r}'.format(key, value))
        return cls_setitem(self, key, value)

    def __delitem__(self, key):
        print('Deleting ' + str(key))
        return cls_delitem(self, key)

    cls.__getitem__ = __getitem__
    cls.__setitem__ = __setitem__
    cls.__delitem__ = __delitem__
    return cls


if __name__ == '__main__':
    d = LoggedDict()
    d['x'] = 23
    print(d['x'])
    d.m = 10
    print(d.m)
